﻿using HalconDotNet;
using KstopaCommon;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace HVision
{
    public class HCircleGuage : HMetrologyShape
    {
        double minRadius = 1;

        double internalRadius, externalRadius;

        PointD pointCenter, pointSymmetry, pointHandle, pointExternal, pointInternal;

        private double col = 150;

        public double Col
        {
            get { return col; }
            set { col = value; }
        }

        private double row = 150;

        public double Row
        {
            get { return row; }
            set { row = value; }
        }

        private double radius = 30;

        public double Radius
        {
            get { return radius; }
            set { radius = value; }
        }

        public HCircleGuage()
        {
            ShapeType = HShapeType.LineGuage;
            numHandles = 4;
            activeHandleIdx = 0;
            HitHandle = HDragHandle.NoHandle;
            pointCenter = new PointD(col, row);
            pointHandle = new PointD(col + radius, row);
            pointInternal = new PointD(col - radius + CaliperHeight, row);
            pointExternal = new PointD(col - radius - CaliperHeight, row);
            pointSymmetry = CalFormula.GetSymmetryOfPointA(pointHandle, pointCenter);
        }

        public override void Measure(HImage image)
        {
            try
            {
                ResultMeasured = new HTuple();
                hMetrology = new HMetrologyModel();
                hContour = null;
                hCross = null;
                hXLDCont = null;
                int width, height;
                image.GetImageSize(out width, out height);
                hMetrology.SetMetrologyModelImageSize(width, height);
                int circleIndex = hMetrology.AddMetrologyObjectCircleMeasure(Row, Col, Radius, CaliperHeight, CaliperWidth, MeasureSigma, MeasureThreshold, new HTuple(), new HTuple());
                //设置测量对象的参数
                //Creating measure regions
                if (distOrNum == false)
                {
                    hMetrology.SetMetrologyObjectParam(circleIndex, "measure_distance", MeasureDistance);
                }
                else
                {
                    hMetrology.SetMetrologyObjectParam(circleIndex, "num_measures", CaliperNum);
                }
                //hMetrology.SetMetrologyObjectParam(circleIndex, "measure_length1", caliperHeight);
                //hMetrology.SetMetrologyObjectParam(circleIndex, "measure_length2", caliperWidth);
                //hMetrology.SetMetrologyObjectParam(circleIndex, "measure_distance", measureDistance);

                //Edge detection
                //hMetrology.SetMetrologyObjectParam(circleIndex, "measure_sigma", MeasureSigma);
                //hMetrology.SetMetrologyObjectParam(circleIndex, "measure_threshold", measureThreshold);
                switch (MeasureTransition)
                {
                    case HTransitionType.Bw:
                        hMetrology.SetMetrologyObjectParam(circleIndex, "measure_transition", "positive");
                        break;
                    case HTransitionType.Wb:
                        hMetrology.SetMetrologyObjectParam(circleIndex, "measure_transition", "negative");
                        break;
                    case HTransitionType.All:
                        hMetrology.SetMetrologyObjectParam(circleIndex, "measure_transition", "all");
                        break;
                }
                hMetrology.SetMetrologyObjectParam(circleIndex, "measure_select", MeasureSelect.ToString());
                hMetrology.SetMetrologyObjectParam(circleIndex, "measure_interpolation", MeasureInterpolation.ToString());

                //Fitting the geometric shapes
                hMetrology.SetMetrologyObjectParam(circleIndex, "min_score", MinScore);
                hMetrology.SetMetrologyObjectParam(circleIndex, "num_instances", NumInstances);
                hMetrology.SetMetrologyObjectParam(circleIndex, "distance_threshold", DistanceThreshold);
                hMetrology.SetMetrologyObjectParam(circleIndex, "max_num_iterations", MaxNumIterations);
                hMetrology.SetMetrologyObjectParam(circleIndex, "rand_seed", RandSeed);
                hMetrology.SetMetrologyObjectParam(circleIndex, "instances_outside_measure_regions", InstancesOutsideMeasureRegions == true ? "true" : "false");

                //执行测量,获取边缘点集
                hMetrology.ApplyMetrologyModel(image);
                hXLDCont = hMetrology.GetMetrologyObjectMeasures("all", "all", out PointsMeasuredRows, out PointsMeasuredCols);
                HOperatorSet.GenCrossContourXld(out hCross, PointsMeasuredRows, PointsMeasuredCols, 6, 0.785398);
                //获取最终测量数据和轮廓线
                ResultMeasured = hMetrology.GetMetrologyObjectResult(circleIndex, "all", "result_type", "all_param");
                hContour = hMetrology.GetMetrologyObjectResultContour("all", "all", 1.5);
                hMetrology.ClearMetrologyObject(circleIndex);
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
                LogHelper.ErrorLog(exc.Message, null);
            }
        }

        public override double DistToClosestHandle(double x, double y)
        {
            double max = 10000;
            double[] val = new double[numHandles];
            val[0] = HMisc.DistancePp(y, x, row, col);
            val[1] = HMisc.DistancePp(y, x, pointHandle.Y, pointHandle.X);
            val[2] = HMisc.DistancePp(y, x, pointInternal.Y, pointInternal.X);
            val[3] = HMisc.DistancePp(y, x, pointExternal.Y, pointExternal.X);

            for (int i = 0; i < numHandles; i++)
            {
                if (val[i] < max)
                {
                    max = val[i];
                    activeHandleIdx = i;
                }
            }
            return val[activeHandleIdx];
        }

        public override void Draw(HWindow hWindow)
        {
            DetermineCaliperHeight();
            pointSymmetry = CalFormula.GetSymmetryOfPointA(pointHandle, pointCenter);


            //画圆
            hWindow.SetDraw("margin");
            hWindow.SetColor("blue");
            hWindow.DispCircle(row, col, radius);
            hWindow.DispCircle(row, col, externalRadius);
            hWindow.DispCircle(row, col, internalRadius);
            hWindow.DispRectangle2(row, col, 0, unitSize, unitSize);

            //画手柄
            hWindow.SetColor("white");
            hWindow.SetDraw("fill");
            hWindow.DispCircle(pointHandle.Y, pointHandle.X, unitSize);
            hWindow.SetColor("black");
            hWindow.DispCircle(pointExternal.Y, pointExternal.X, unitSize);
            hWindow.DispCircle(pointInternal.Y, pointInternal.X, unitSize);

            ////画黑白指向箭头
            //hWindow.SetDraw("fill");
            //hWindow.SetColor("black");
            //hWindow.DispRectangle2(0.5 * (iconUpperMid.Y + iconMid.Y), 0.5 * (iconUpperMid.X + iconMid.X), -Phi, 6, 9);
            //hWindow.SetColor("white");
            //hWindow.DispRectangle2(0.5 * (iconLowerMid.Y + iconMid.Y), 0.5 * (iconLowerMid.X + iconMid.X), -Phi, 6, 9);
            //PointD triangleLeft, triangleRight, triangleMid;
            //HRegion hRegion = null;
            //HTuple rows = new HTuple(), cols = new HTuple();
            //switch (MeasureTransition)//20*60,10
            //{
            //    case HTransitionType.Bw:
            //        hRegion = new HRegion();
            //        triangleLeft = new PointD((2 * iconUpperLeft.X + iconLowerLeft.X) / 3, (2 * iconUpperLeft.Y + iconLowerLeft.Y) / 3);
            //        triangleRight = new PointD((2 * iconUpperRight.X + iconLowerRight.X) / 3, (2 * iconUpperRight.Y + iconLowerRight.Y) / 3);
            //        triangleMid = new PointD((iconUpperMid.X + 2 * iconLowerMid.X) / 3, (iconUpperMid.Y + 2 * iconLowerMid.Y) / 3);
            //        rows.Append(triangleLeft.Y);
            //        rows.Append(triangleMid.Y);
            //        rows.Append(triangleRight.Y);
            //        rows.Append(triangleLeft.Y);
            //        cols.Append(triangleLeft.X);
            //        cols.Append(triangleMid.X);
            //        cols.Append(triangleRight.X);
            //        cols.Append(triangleLeft.X);
            //        hRegion.GenRegionPolygonFilled(rows, cols);
            //        hWindow.SetColor(new HTuple("#7F7F7F"));
            //        hWindow.DispObj(hRegion);
            //        break;
            //    case HTransitionType.Wb:
            //        hRegion = new HRegion();
            //        triangleLeft = new PointD((iconUpperLeft.X + 2 * iconLowerLeft.X) / 3, (iconUpperLeft.Y + 2 * iconLowerLeft.Y) / 3);
            //        triangleRight = new PointD((iconUpperRight.X + 2 * iconLowerRight.X) / 3, (iconUpperRight.Y + 2 * iconLowerRight.Y) / 3);
            //        triangleMid = new PointD((2 * iconUpperMid.X + iconLowerMid.X) / 3, (2 * iconUpperMid.Y + iconLowerMid.Y) / 3);
            //        rows.Append(triangleLeft.Y);
            //        rows.Append(triangleMid.Y);
            //        rows.Append(triangleRight.Y);
            //        rows.Append(triangleLeft.Y);
            //        cols.Append(triangleLeft.X);
            //        cols.Append(triangleMid.X);
            //        cols.Append(triangleRight.X);
            //        cols.Append(triangleLeft.X);
            //        hRegion.GenRegionPolygonFilled(rows, cols);
            //        hWindow.SetColor(new HTuple("#7F7F7F"));
            //        hWindow.DispObj(hRegion);
            //        break;
            //    case HTransitionType.All:
            //    default:
            //        break;
            //}
            //hWindow.SetDraw("margin");
            //hWindow.SetColor("blue");
            //hWindow.DispLine(iconLowerLeft.Y, iconLowerLeft.X, iconUpperLeft.Y, iconUpperLeft.X);
            //hWindow.DispLine(iconLowerLeft.Y, iconLowerLeft.X, iconLowerRight.Y, iconLowerRight.X);
            //hWindow.DispLine(iconLowerRight.Y, iconLowerRight.X, iconUpperRight.Y, iconUpperRight.X);
            //hWindow.DispLine(iconUpperRight.Y, iconUpperRight.X, iconUpperLeft.Y, iconUpperLeft.X);

        }

        public override HRegion GetRegion()
        {
            throw new NotImplementedException();
        }

        public override void MoveByHandle(double x, double y)
        {
            switch (activeHandleIdx)
            {
                case 0: // center
                    double offsety = y - row;
                    double offsetx = x - col;
                    row = y;
                    col = x;
                    pointCenter.Y += offsety;
                    pointCenter.X += offsetx;
                    pointHandle.Y += offsety;
                    pointHandle.X += offsetx;
                    pointExternal.Y += offsety;
                    pointExternal.X += offsetx;
                    pointInternal.Y += offsety;
                    pointInternal.X += offsetx;
                    pointSymmetry.Y += offsety;
                    pointSymmetry.X += offsetx;
                    break;
                case 1: // handle
                    pointHandle.Y = y;
                    pointHandle.X = x;
                    radius = HMisc.DistancePp(pointHandle.Y, pointHandle.X, row, col);
                    DetermineCaliperHeight();
                    pointExternal = CalFormula.GetPointOfExtensionLine(pointHandle, pointCenter, radius + CaliperHeight);
                    pointInternal = CalFormula.GetPointOfExtensionLine(pointHandle, pointCenter, radius - CaliperHeight);
                    pointSymmetry = CalFormula.GetSymmetryOfPointA(pointHandle, pointCenter);
                    break;
                case 2: // Internal 
                    double dist_internal = Math.Abs(HMisc.DistancePp(y, x, row, col));
                    pointInternal = CalFormula.GetPointOfExtensionLine(pointInternal, pointCenter, -dist_internal);
                    internalRadius = HMisc.DistancePp(row, col, pointInternal.Y, pointInternal.X);
                    CaliperHeight = Math.Abs(radius - internalRadius);
                    pointExternal = CalFormula.GetPointOfExtensionLine(pointCenter, pointInternal, 2 * (radius - internalRadius));
                    externalRadius = HMisc.DistancePp(row, col, pointExternal.Y, pointExternal.X);
                    break;
                case 3: // External
                    double dist_external = Math.Abs(HMisc.DistancePp(y, x, row, col));
                    pointExternal = CalFormula.GetPointOfExtensionLine(pointExternal, pointCenter, -dist_external);
                    externalRadius = HMisc.DistancePp(row, col, pointExternal.Y, pointExternal.X);
                    CaliperHeight = Math.Abs(radius - externalRadius);
                    pointInternal = CalFormula.GetPointOfExtensionLine(pointCenter, pointExternal, 2 * (radius - externalRadius));
                    internalRadius = HMisc.DistancePp(row, col, pointInternal.Y, pointInternal.X);
                    break;
            }
        }

        private void DetermineCaliperHeight()
        {
            if (radius - CaliperHeight < minRadius)
            {
                CaliperHeight = radius - minRadius;
                internalRadius = minRadius;
                externalRadius = radius + CaliperHeight;
            }
            else
            {
                internalRadius = radius - CaliperHeight;
                externalRadius = radius + CaliperHeight;
            }
        }

    }
}
